/**
  ******************************************************************************
  * @file    socket-util.h
  * @author  Dragon.Chen
  * @version V1.0.2
  * @date    11-08-2018
  * @brief   socket通用函数接口
  * @project linux client
  ******************************************************************************
  * @attention
  *
  * <h2><center>&copy; COPYRIGHT 2018 上海今中网络科技有限公司 </center></h2>
  ******************************************************************************
  */

#include "socket-util.h"
/**
  * @brief  设置socket阻塞状态
  * @param  arg1:fd
  * @retval	成功返回0, 失败返回-1
  */
int setblocking(int fd)
{
	int val;

	if ((val = fcntl(fd, F_GETFL, 0)) < 0)
		return -1;
	val &= ~O_NONBLOCK;
	if (fcntl(fd, F_SETFL, val) < 0)
		return -1;
	return 0;
}

/**
  * @brief  设置socket非阻塞状态
  * @param  arg1:fd
  * @retval	成功返回0, 失败返回-1
  */
int setnonblocking(int fd)
{
	int val;

	if ((val = fcntl(fd, F_GETFL, 0)) < 0)
		return -1;
	val |= O_NONBLOCK;
	if (fcntl(fd, F_SETFL, val) < 0)
		return -1;
	return 0;
}

/**
  * @brief  非阻塞连接
  * @param  arg1 ip  arg2 port arg3 超时时间
  * @retval 返回监听fd,失败程序exit
  */
int tcp_connect(const char *ip, int port, int time)
{
	int                 retval;
	int                 sockfd;
    int                 error;
    socklen_t           length;
    fd_set              writefds;
    struct timeval      timeout;
	struct sockaddr_in  address;

	memset(&address, 0, sizeof(address));
	address.sin_family = AF_INET;
	address.sin_port = htons(port);
	address.sin_addr.s_addr = inet_addr(ip);

	/// 设置socket非阻塞
    if ((sockfd = socket(AF_INET, SOCK_STREAM, 0)) < 0)
        return -1;
    if (setnonblocking(sockfd) < 0)
    {
        goto cleanup;
    }

    /// 连接成功恢复socket属性
    retval = connect(sockfd, (struct sockaddr*)&address, sizeof(address));
    if (retval == 0)
    {
    	if (setblocking(sockfd) < 0)
        {
            goto cleanup;
        }
    	else
        {
            return sockfd;
        }
    }
    /// EINPROGRESS为连接正在进行
    else if (errno != EINPROGRESS)
    {
    	goto cleanup;
    }

    FD_ZERO(&writefds);
    FD_SET(sockfd, &writefds);
    timeout.tv_sec  = time;
    timeout.tv_usec = 0;
    retval = select(sockfd+1, NULL, &writefds, NULL, &timeout);
    if (retval <= 0)
    {
        goto cleanup;
    }

    if (!FD_ISSET(sockfd, &writefds))
    {
        goto cleanup;
    }

    /// 清除sockfd上错误
    error           = 0;
    length          = sizeof(error);
    if (getsockopt(sockfd, SOL_SOCKET, SO_ERROR, &error, &length) < 0)
    {
        goto cleanup;
    }

    /// 错误不为0表示连接出错
    if (error != 0)
    {
        goto cleanup;
    }
    /// 连接成功
    if (setblocking(sockfd) < 0)
    {
        goto cleanup;
    }

    return sockfd;

cleanup:
	close(sockfd);
	return -1;
}


/******************* (C) COPYRIGHT 2018 上海今中网络科技有限公司 *****END OF FILE****/



















